home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
tools
/
jade
/
src
/
unix_server.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
7KB
|
252 lines
/* unix_server.c -- client/server file handling
Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
_PR void server_init(void);
_PR void server_kill(void);
#define JADE_SOCK_NAME "~/.Jade_rendezvous"
/* List of (FILE-NAME . SOCK-FD) */
static VALUE client_list;
static VALUE sym_server_open_file;
/* fd of the socket which clients connect to, or zero. */
static int socket_fd = -1;
/* pathname of the socket. */
static VALUE socket_name;
static void
server_accept_connection(int unused_fd)
{
int confd = accept(socket_fd, NULL, NULL);
if(confd >= 0)
{
/* 1. read length field
2. read LENGTH bytes for the filename
3. read the line number
4. add (FILE . SOCK-FD) to list of client files
5. call client-open-file with FILE and LINE */
u_short filenamelen;
u_long tmp;
VALUE filename, linenum;
if(read(confd, &filenamelen, sizeof(u_short)) != sizeof(u_short))
goto readerror;
filename = make_string(filenamelen + 1);
if(read(confd, VSTR(filename), filenamelen) != filenamelen)
goto readerror;
VSTR(filename)[filenamelen] = 0;
if(read(confd, &tmp, sizeof(u_long)) != sizeof(u_long))
{
readerror:
cmd_signal(sym_error,
LIST_1(MKSTR("server_make_connection:read")));
return;
}
linenum = make_number(tmp - 1);
client_list = cmd_cons(cmd_cons(filename, make_number(confd)),
client_list);
/* lose this on exec() */
fcntl(confd, F_SETFD, 1);
cursor(curr_vw, CURS_OFF);
call_lisp2(sym_server_open_file, filename, linenum);
cursor(curr_vw, CURS_ON);
}
}
_PR VALUE cmd_server_open_p(void);
DEFUN("server-open-p", cmd_server_open_p, subr_server_open_p, (void), V_Subr0, DOC_server_open_p) /*
::doc:server_open_p::
server-open-p
t if the edit-server is open.
::end:: */
{
if(socket_fd >= 0)
return(sym_t);
return(sym_nil);
}
_PR VALUE cmd_server_open(void);
DEFUN_INT("server-open", cmd_server_open, subr_server_open, (void), V_Subr0, DOC_server_open, "") /*
::doc:server_open::
server-open
Creates the socket (or whatever) so that the editor's client program can
send us messages.
::end:: */
{
VALUE name;
if(socket_fd >= 0)
return(sym_t);
name = cmd_expand_file_name(MKSTR(JADE_SOCK_NAME), sym_nil);
if(name && STRINGP(name))
{
VALUE tmp = cmd_file_exists_p(name);
if(!tmp || !NILP(tmp))
{
message("A server is already open.");
return(sym_nil);
}
socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if(socket_fd >= 0)
{
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, VSTR(name));
if(bind(socket_fd, (struct sockaddr *)&addr,
sizeof(addr.sun_family) + strlen(addr.sun_path)) == 0)
{
if(listen(socket_fd, 5) == 0)
{
/* lose this on exec() */
fcntl(socket_fd, F_SETFD, 1);
fcntl(socket_fd, F_SETFL, O_NONBLOCK);
#ifdef HAVE_X11
/* for the x11 eventloop */
x11_fd_read_action[socket_fd] = server_accept_connection;
FD_SET(socket_fd, &x11_fd_read_set);
#endif
socket_name = name;
return(sym_t);
}
else
signal_file_error(MKSTR("bind()"));
}
else
signal_file_error(MKSTR("listen()"));
}
else
cmd_signal(sym_error, LIST_1(MKSTR("Can't make socket name")));
close(socket_fd);
socket_fd = -1;
}
else
signal_file_error(MKSTR("socket()"));
return(NULL);
}
_PR VALUE cmd_server_close(void);
DEFUN_INT("server-close", cmd_server_close, subr_server_close, (void), V_Subr0, DOC_server_close, "") /*
::doc:server_close::
server-close
Stops listening for client messages.
::end:: */
{
if(socket_fd > 0)
{
#ifdef HAVE_X11
x11_fd_read_action[socket_fd] = NULL;
FD_CLR(socket_fd, &x11_fd_read_set);
#endif
close(socket_fd);
socket_fd = -1;
unlink(VSTR(socket_name));
socket_name = NULL;
}
return(sym_t);
}
_PR VALUE cmd_server_reply(VALUE file, VALUE rc);
DEFUN("server-reply", cmd_server_reply, subr_server_reply, (VALUE file, VALUE rc), V_Subr2, DOC_server_reply) /*
::doc:server_reply::
server-reply [FILE-NAME] [RETURN-CODE]
Replies to the editor client which asked us to edit the file FILE-NAME.
RETURN-CODE is the optional result for the client, by default it is zero
which denotes no errors. Returns nil if the file doesn't have a client.
::end:: */
{
VALUE res = sym_nil;
VALUE tmp = client_list;
if(BUFFERP(file))
file = VTX(file)->tx_FileName;
else if(!STRINGP(file))
file = curr_vw->vw_Tx->tx_FileName;
client_list = sym_nil;
while(CONSP(tmp))
{
register VALUE car = VCAR(tmp);
VALUE next = VCDR(tmp);
if(!VALUE_CMP(file, VCAR(car)))
{
/* Send the result to our client. */
int con_fd = VNUM(VCDR(car));
u_long result = NUMBERP(rc) ? VNUM(rc) : 0;
if(write(con_fd, &result, sizeof(result)) != sizeof(result))
res = signal_file_error(file);
else
res = sym_t;
close(con_fd);
}
else
{
VCDR(tmp) = client_list;
client_list = tmp;
}
tmp = next;
}
return(res);
}
void
server_init(void)
{
client_list = sym_nil;
mark_static(&client_list);
mark_static(&socket_name);
INTERN(sym_server_open_file, "server-open-file");
ADD_SUBR(subr_server_open_p);
ADD_SUBR(subr_server_open);
ADD_SUBR(subr_server_close);
ADD_SUBR(subr_server_reply);
}
void
server_kill(void)
{
/* clean up */
VALUE tmp = client_list;
while(CONSP(tmp))
{
/* Any client-opened files still around are replied to with
a result of 5 (fail). */
static u_long failrc = 5;
int fd = VNUM(VCDR(VCAR(tmp)));
write(fd, &failrc, sizeof(u_long));
close(fd);
tmp = VCDR(tmp);
}
client_list = sym_nil;
cmd_server_close();
}